/*
 * AttributeGroup.java
 *
 * Created on 20 marzo 2004, 10.41
 */

package net.ermannofranco.xml.schema;

import net.ermannofranco.xml.Static;

/**
 * 
 * @author ermanno (ermanno.franco@gmail.com)
 */
public class AttributeGroup extends SchemaTag {

	private static final long serialVersionUID = -1886670193198361867L;
	private boolean named;

	private boolean content;
	private AnyAttribute anyAttribute;
	private boolean refAssigned;

	/**
	 * Creates a new instance of AttributeGroup Protetto
	 * 
	 * @param level
	 *            livello di indentazione
	 * @param container
	 *            tag contenitore
	 */
	protected AttributeGroup(int level, ISchemaTag container) {
		super("attributeGroup", level, container);
	}

	/**
	 * @param ref
	 * @return
	 */
	public AttributeGroup setRef(AttributeGroup ref) {
		if (content)
			throw new SchemaException(
					"impossibile assegnare ref; contenuto gia' assegnato, "
							+ getClass().getName() + ":(" + getName() + ")");
		if (getLevel() == 1)
			throw new SchemaException("Cannot set ref in first level, "
					+ getClass().getName() + ":(" + getName() + ")");

		addAttr("ref", feedFormPrefix(ref.getAttribute("name")));
		named = true;
		refAssigned=true;
		return this;
	}

	/**
	 * @param name
	 * @return
	 */
	public AttributeGroup setName(String name) {
		if (getLevel() != 1)
			throw new SchemaException("Cannot set name in inner level, "
					+ getClass().getSimpleName() + ":(" + getName() + ")");
		Static.validateNMToken(name);

		addAttr("name", name);
		named = true;
		return this;
	}

	/**
	 * @return
	 */
	public AttributeGroup addAttributeGroup() {
		if (refAssigned)
			throw new SchemaException(
					"impossibile assegnare contenuto; ref gia' assegnato, "
							+ getClass().getName() + ":(" + getName() + ")");
		
		AttributeGroup ag;
		add(ag = new AttributeGroup(getLevel() + 1, this));
		content = true;
		return ag;
	}

	// public Attribute addTagAttribute() {
	// // if (gestoreContenuto == 0)
	// // throw new SchemaException(
	// // "Assegnare contenuto prima di addAttributeTag");
	// Attribute att;
	// add(att = new Attribute(getLevel() + 1, this));
	// return att;
	// }

	/**
	 * add a "Attribute" tag with given name.
	 * 
	 * @return Attribute
	 */
	public Attribute addTagAttribute(String name) {
		if (refAssigned)
			throw new SchemaException(
					"impossibile assegnare contenuto; ref gia' assegnato, "
							+ getClass().getName() + ":(" + getName() + ")");

		Attribute att;
		add(att = new Attribute(getLevel() + 1, this));
		att.setName(name);
		return att;
	}

	/**
	 * add a "Attribute" tag with given name and use.
	 * 
	 * @return Attribute
	 */
	public Attribute addTagAttribute(String name, Use use) {
		Attribute ret = addTagAttribute(name);
		ret.setUse(use);
		return ret;
	}

	/**
	 * add a "Attribute" tag with given reference.
	 * 
	 * @return Attribute
	 */
	public Attribute addTagAttribute(Attribute ref) {
		if (refAssigned)
			throw new SchemaException(
					"impossibile assegnare contenuto; ref gia' assegnato, "
							+ getClass().getName() + ":(" + getName() + ")");

		Attribute att;
		add(att = new Attribute(getLevel() + 1, this));
		att.setRef(ref);
		return att;
	}

	/**
	 * add a "Attribute" tag with given reference and use.
	 * 
	 * @return Attribute
	 */
	public Attribute addTagAttribute(Attribute ref, Use use) {
		Attribute att=addTagAttribute(ref);	
		return att.setUse(use);
	}

	/**
	 * add a "Attribute" tag with given name and type.
	 * 
	 * @return Attribute
	 */
	public Attribute addTagAttribute(String name, XmlType type) {
		Attribute ret = addTagAttribute(name);		
		return ret.setType(type);
	}

	/**
	 * add a "Attribute" tag with given name, type and use.
	 * 
	 * @return Attribute
	 */
	public Attribute addTagAttribute(String name, XmlType type, Use use) {
		Attribute ret = addTagAttribute(name);		
		return ret.setType(type).setUse(use);
	}

	/**
	 * add a "Attribute" tag with given name and type reference.
	 * 
	 * @return Attribute
	 */
	public Attribute addTagAttribute(String name, ContentType typeRef) {
		Attribute ret = addTagAttribute(name);		
		return ret.setType(typeRef);
	}

	/**
	 * add a "Attribute" tag with given name, type reference and use.
	 * 
	 * @return Attribute
	 */
	public Attribute addTagAttribute(String name, ContentType typeRef, Use use) {
		Attribute ret = addTagAttribute(name, typeRef);
		ret.setUse(use);
		return ret;
	}

	/**
	 * add a "Attribute" tag with given name and type name.
	 * 
	 * @return Attribute
	 */
	public Attribute addTagAttribute(String name, String typeName) {
		Attribute ret = addTagAttribute(name);
		ret.setType(typeName);
		return ret;
	}

	/**
	 * add a "Attribute" tag with given name, type name and use.
	 * 
	 * @return Attribute
	 */
	public Attribute addTagAttribute(String name, String typeName, Use use) {
		Attribute ret = addTagAttribute(name, typeName);
		ret.setUse(use);
		return ret;
	}

	public AnyAttribute setAnyAttribute() {
		if (refAssigned)
			throw new SchemaException(
					"impossibile assegnare contenuto; ref gia' assegnato, "
							+ getClass().getName() + ":(" + getName() + ")");

		if (anyAttribute != null)
			throw new SchemaException("AnyAttribute gia' assegnato, "
					+ getClass().getName() + ":(" + getName() + ")");
		anyAttribute = new AnyAttribute(getLevel() + 1, this);
		content = true;
		return anyAttribute;
	}

	public AnyAttribute setAnyAttribute(String... namespace) {
		return setAnyAttribute().setNamespace(namespace);
	}

	public AnyAttribute setAnyAttribute(NsConstants namespace,
			Process processContent) {
		return setAnyAttribute().setNamespace(namespace.getVal())
				.processContents(processContent);
	}

	public AnyAttribute setAnyAttribute(Process processContent) {
		return setAnyAttribute().processContents(processContent);
	}

	/**
	 * aggiunge un tag Annotation che contiene un tag Documentation
	 * 
	 * @param explanation
	 *            Stringa di documentazione
	 * @return autoriferimento all'oggetto corrente
	 */
	public AttributeGroup addDocumentation(String explanation) {
		addAnnotation().addDocumentation(explanation);
		return this;
	}

	/**
	 * aggiunge un tag Annotation che contiene un tag Documentation
	 * 
	 * @param explanation
	 *            testo della documentazione
	 * @param language
	 *            attributo di xml:lang, seguire le regole di i18n
	 * @return riferimento all'oggetto corrente
	 */
	public AttributeGroup addDocumentation(String explanation, String language) {
		addAnnotation().addDocumentation(explanation, language);
		return this;
	}

	private void validateAttr() {
		if (!named)
			throw new SchemaException("ref or name are mandatory, "
					+ getClass().getName() + ":(" + getName() + ")");
	}

	@Override
	public String toPrint() {
		validateAttr();
		return super.toPrint();
	}

	@Override
	public String toSave() {
		validateAttr();
		return super.toSave();
	}

}
